package com.xy.service.common;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xy.api.constant.enums.JuheExchangeRateCodeEnum;
import com.xy.api.constant.enums.UnitTypeEnum;
import com.xy.api.exception.BizException;
import com.xy.api.model.dto.common.UnitDTO;
import com.xy.api.model.request.common.UnitRequest;
import com.xy.api.service.common.IUnitService;
import com.xy.auth.UserContext;
import com.xy.mapper.common.UnitMapper;
import com.xy.model.po.common.UnitPO;
import com.xy.utils.CustomBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
@Service
public class UnitServiceImpl implements IUnitService {

    @Autowired
    private UnitMapper unitMapper;

    @Autowired
    private RestTemplate restTemplate;

    @Value("${juhe.apiKey:521eedba7c2a55e193046827aa870615}")
    private String juheApiKey;

    @Override
    public List<UnitDTO> queryUnitList(UnitRequest request) {
        Assert.notNull(request.getType(), "单位类型必填");
        LambdaQueryWrapper<UnitPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(UnitPO::getIsDeleted, 0)
                .eq(UnitPO::getType, request.getType());
        List<UnitPO> unitPOS = unitMapper.selectList(queryWrapper);
        List<UnitDTO> unitList = CustomBeanUtil.copyListProperties(unitPOS, UnitDTO::new);
        return unitList;
    }

    @Override
    public UnitDTO queryUnitDetail(Long id) {
        Assert.notNull(id, "单位ID必填");
        UnitDTO result = new UnitDTO();
        UnitPO unitPO = unitMapper.selectById(id);
        CustomBeanUtil.copyProperties(unitPO, result);
        return result;
    }

    @Override
    public void editUnit(UnitDTO request) {
        Assert.notNull(request.getType(), "单位类型必填");
        Assert.hasText(request.getCode(), "单位代码必填");
        Assert.hasText(request.getName(), "单位名称必填");
        Assert.notNull(request.getFactor(), "同主单位的转换因子必填");
        UnitPO unit = new UnitPO();
        unit.setId(request.getId());
        if (Objects.equals(1, request.getPrimaryUnit())) {
            throw new BizException("主单位不可编辑");
        }
        if (BigDecimal.ZERO.compareTo(request.getFactor()) >= 0) {
            throw new BizException("转换因子必须大于0");
        }
        unit.setType(request.getType());
        unit.setCode(request.getCode());
        unit.setName(request.getName());
        unit.setFactor(request.getFactor());
        unit.setPrimaryUnit(0);

        if (null != unit.getId()) {
            updateUnit(unit);
        } else {
            addUnit(unit);
        }
    }

    /**
     * 更新单位
     *
     * @param unit
     */
    private void updateUnit(UnitPO unit) {
        UnitPO existUnit = unitMapper.selectById(unit.getId());
        if (Objects.equals(existUnit.getType(), unit.getType())) {
            throw new BizException("不允许变更单位类型");
        }
        if (Objects.equals(existUnit.getPrimaryUnit(), 1)) {
            throw new BizException("主单位不允许更改");
        }
        unit.setUpdateBy(UserContext.get().getId());
        unitMapper.updateById(unit);
    }

    /**
     * 新增单位
     *
     * @param unit
     */
    private void addUnit(UnitPO unit) {
        unit.setUpdateBy(UserContext.get().getId());
        unitMapper.insert(unit);
    }

    @Override
    public void deleteUnit(Long id) {
        Assert.notNull(id, "单位ID必填");
        UnitPO existUnit = unitMapper.selectById(id);
        if (null != existUnit && Objects.equals(existUnit.getPrimaryUnit(), 1)) {
            throw new BizException("主单位不可删除");
        }

        UnitPO deleteRecord = new UnitPO();
        deleteRecord.setId(id);
        deleteRecord.setIsDeleted(1);
        deleteRecord.setUpdateBy(UserContext.get().getId());
        unitMapper.updateById(deleteRecord);
    }

    @Override
    public BigDecimal convertUnit(Integer type, String fromUnitCode, String toUnitCode, BigDecimal value) {
        Assert.notNull(type, "单位类型必填");
        Assert.hasText(fromUnitCode, "来源单位必填");
        Assert.hasText(toUnitCode, "目标单位必填");
        Assert.notNull(value, "值不能为空");
        if (BigDecimal.ZERO.compareTo(value) == 0) {
            throw new BizException("值不能为0");
        }
        if (Objects.equals(fromUnitCode, toUnitCode)) {
            return value;
        }
        List<String> unitCodeList = new ArrayList<>();
        unitCodeList.add(fromUnitCode);
        unitCodeList.add(toUnitCode);
        LambdaQueryWrapper<UnitPO> query = new LambdaQueryWrapper<>();
        query.eq(UnitPO::getIsDeleted, 0)
                .eq(UnitPO::getType, type)
                .in(UnitPO::getCode, unitCodeList);
        List<UnitPO> unitPOS = unitMapper.selectList(query);

        if (CollectionUtils.isEmpty(unitPOS) || unitPOS.size() != 2) {
            throw new BizException("单位配置异常，请检查单位配置");
        }
        UnitPO fromUnit = null, toUnit = null;
        for (UnitPO unitPO : unitPOS) {
            if (Objects.equals(unitPO.getCode(), fromUnitCode)) {
                fromUnit = unitPO;
            } else if (Objects.equals(unitPO.getCode(), toUnitCode)) {
                toUnit = unitPO;
            }
        }
        return value.multiply(fromUnit.getFactor()).divide(toUnit.getFactor(), 6, RoundingMode.HALF_UP);
    }

    @Override
    public List<UnitDTO> getExchangeRate() {
        Map<String, String> param = new HashMap<>();
        param.put("key", juheApiKey);
        param.put("type", "1");
        String url = "http://web.juhe.cn/finance/exchange/frate?key={key}&type={type}";
        List<UnitDTO> exchangeRateList = new ArrayList<>();

        try {
            String res = restTemplate.getForObject(url, String.class, param);
            log.info("enter getExchangeRate,res:{}", res);
            JSONObject jsonObject = JSON.parseObject(res);
            Integer resultCode = jsonObject.getInteger("resultcode");
            if (null == resultCode || 200 != resultCode) {
                throw new BizException("获取实时汇率失败");
            }
            JSONArray jsonArray = jsonObject.getJSONArray("result");
            Map<String, JSONObject> map = jsonArray.getObject(0, Map.class);

            for (Map.Entry<String, JSONObject> entry : map.entrySet()) {
                String key = entry.getKey();
                JuheExchangeRateCodeEnum juheExchangeRateCode = JuheExchangeRateCodeEnum.fromCode(key);
                if (null == juheExchangeRateCode) {
                    continue;
                }

                JSONObject value = entry.getValue();
                String closePri = value.getString("closePri");
                Date date = value.getDate("date");

                UnitDTO record = new UnitDTO();
                record.setType(UnitTypeEnum.EXCHANGE_RATE.getCode());
                record.setCode(juheExchangeRateCode.getUnitCode());
                record.setName(juheExchangeRateCode.getUnitName());
                record.setPrimaryUnit(0);
                record.setFactor(BigDecimal.valueOf(Double.valueOf(closePri)).setScale(4, RoundingMode.HALF_UP));
                record.setEffectTime(date);
                exchangeRateList.add(record);
            }
            UnitDTO USDRecord = new UnitDTO();
            USDRecord.setType(UnitTypeEnum.EXCHANGE_RATE.getCode());
            USDRecord.setCode("USD");
            USDRecord.setName("美元");
            USDRecord.setPrimaryUnit(1);
            USDRecord.setFactor(BigDecimal.valueOf(1));
            USDRecord.setEffectTime(new Date());
            exchangeRateList.add(USDRecord);
        } catch (Exception ex) {
            log.error("getExchangeRate error", ex);
            throw new BizException("获取实时汇率失败");
        }
        return exchangeRateList;
    }

    @Override
    @Transactional
    public void updateExchangeRate() {
        List<UnitDTO> exchangeRateList = getExchangeRate();
        if (CollectionUtils.isEmpty(exchangeRateList)) {
            return;
        }
        LambdaQueryWrapper<UnitPO> deleteQuery = new LambdaQueryWrapper<>();
        deleteQuery.eq(UnitPO::getType, UnitTypeEnum.EXCHANGE_RATE.getCode());

        UnitPO deleteRecord = new UnitPO();
        deleteRecord.setIsDeleted(1);
        unitMapper.update(deleteRecord, deleteQuery);

        List<UnitPO> unitPOS = CustomBeanUtil.copyListProperties(exchangeRateList, UnitPO::new);
        unitMapper.batchInsert(unitPOS);
    }
}
